package com.chinamsp.xls;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * 处理 xls/xlsx 视图数据
 * @author shifenghu
 * @version 1.0
 */
public class XlsMessageConverter implements HttpMessageConverter<XlsViewModel>{

	
	/**
	 * xls 类型数据
	 */
	public static final String XLS_CONTENT_TYPE = "application/vnd.ms-excel";
	
	/**
	 * xlsx 类型数据
	 */
	public static final String XLSX_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
	
	/**
	 * xlsx 扩展名
	 */
	private static final String XLSX_EXTENSION = ".xlsx";
	
	/**
	 * xls 扩展名
	 */
	private static final String XLS_EXTENSION = ".xls";
	
	/**
	 * xls 类型
	 */
	private static final MediaType XLS_MEDIA_TYPE = MediaType.parseMediaType(XLS_CONTENT_TYPE);
	
	/**
	 * xlsx 类型
	 */
	private static final MediaType XLSX_MEDIA_TYPE = MediaType.parseMediaType(XLSX_CONTENT_TYPE);
	
	
	@Override
	public boolean canRead(Class<?> clazz, MediaType mediaType) {
		return false;
	}

	@Override
	public boolean canWrite(Class<?> clazz, MediaType mediaType) {
		return clazz == XlsViewModel.class;
	}

	@Override
	public List<MediaType> getSupportedMediaTypes() {
		return Arrays.asList(XLS_MEDIA_TYPE, XLSX_MEDIA_TYPE);
	}

	@Override
	public XlsViewModel read(Class<? extends XlsViewModel> clazz, HttpInputMessage inputMessage)
			throws IOException, HttpMessageNotReadableException {
		return null;
	}

	@Override
	public void write(XlsViewModel t, MediaType contentType, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException {
		Assert.notNull(t, "解析的数据模型 不能为空");
		// 文件名
		if (!StringUtils.isEmpty(t.getFileName())){
			outputMessage.getHeaders().add("Content-Disposition", "attachment; filename=" + fileName(contentType, t.getFileName()));
		}
		// 内容类型
		outputMessage.getHeaders().add("Content-Type", XLS_MEDIA_TYPE.isCompatibleWith(contentType)  ? XLS_MEDIA_TYPE.toString() : XLSX_MEDIA_TYPE.toString());
		write(t.getContext(), t.getTemplateUrl(), outputMessage.getBody());
	}
	
	/**
	 * 生成 文件名
	 * @param mediaType
	 * @param fileName
	 * @return
	 * @throws IOException
	 */
	protected String fileName(MediaType mediaType, String fileName) throws IOException{
		return URLEncoder.encode(fileName, "UTF-8") + ( XLS_MEDIA_TYPE.isCompatibleWith(mediaType)  ? XLS_EXTENSION : XLSX_EXTENSION);
	}

	/**
	 * 输出文件
	 * 
	 * @param context
	 * @param out
	 */
	protected void write(Map<String, Object> context, String templateUrl, OutputStream out) {
		Assert.notNull(context, "context 不能为空");
		Assert.notNull(templateUrl, "template url 不能为空");
		Assert.notNull(out, "outputstream 不能为空");
		try {
			new ExtendedXlsTransformer().transformXLS(templateUrl, context, out);
		} catch (Exception e) {
			throw new IllegalArgumentException("输出 excel 失败", e);
		}
	}
}
